#include "ffmpegutil.h"

// 处理错误码
#define ERROR_BUF(ret) \
    char errbuf[1024]; \
    av_strerror(ret, errbuf, sizeof (errbuf));

FFmpegUtil::FFmpegUtil()
{

}


void FFmpegUtil::resampleAudio(ResampleAudioSpec &in,
                               ResampleAudioSpec &out) {
    resampleAudio(in.filename,in.sampleRate,in.sampleFmt,in.chLayout,
                  out.filename,out.sampleRate,out.sampleFmt,out.chLayout);
}

void FFmpegUtil::resampleAudio(const char *inFilename,
                               int inSampleRate,
                               AVSampleFormat inSampleFmt,
                               int inChLayout,

                               const char *outFilename,
                               int outSampleRate,
                               AVSampleFormat outSampleFmt,
                               int outChLayout){
    // 文件名
    QFile inFile(inFilename);
    QFile outFile(outFilename);

    // 输入缓冲区的变量
    // 指向缓冲区的指针
    uint8_t **inAudioData = nullptr;
    // 缓冲去的大小
    int inLinesize = 0;
     // 声道数
    int inNbChannels = av_get_channel_layout_nb_channels(inChLayout);
    // 一个样本的大小
    int inBytesPerSample = inNbChannels * av_get_bytes_per_sample(inSampleFmt);
    // 缓冲区的样本数
    int inNbSamples = 1024;
    // 读取文件的大小
    int len = 0;


    // 输出缓冲区的变量
    // 指向缓冲区的指针
    uint8_t **outAudioData = nullptr;
    // 缓冲去的大小
    int outLinesize = 0;
    // 声道数
    int outNbChannels = av_get_channel_layout_nb_channels(outChLayout);
    // 一个样本的大小
    int outBytesPerSample = outNbChannels * av_get_bytes_per_sample(outSampleFmt);
    // 缓冲区的样本数
    int outNbSamples = av_rescale_rnd(outSampleRate,inNbSamples,inSampleRate,AV_ROUND_UP);
    /*
     inSampleRate     inSamples
     ------------- = -----------
     outSampleRate    outSamples

     outSamples = outSampleRate * inSamples / inSampleRate
     */

    qDebug() << "输入缓冲区"<< inSampleRate << inNbSamples ;
    qDebug() << "输出缓冲区"<< outSampleRate << outNbSamples ;

    // 返回结果
    int ret = 0;

    // 创建重采样上下文
    SwrContext *ctx = swr_alloc_set_opts(nullptr,
                                         // 输出参数
                                         outChLayout,outSampleFmt,outSampleRate,
                                         // 输入参数
                                         inChLayout,inSampleFmt,inSampleRate,
                                         0,nullptr);
    if(!ctx){
        qDebug() << "swr_alloc_set_opts error";
        goto end;
    }

    // 初始化重采样上下文
    ret = swr_init(ctx);
    if (ret < 0) {
        ERROR_BUF(ret);
        qDebug() << "swr_init error:" << errbuf;
        goto end;
    }

    // 创建输入缓冲区
    ret = av_samples_alloc_array_and_samples(&inAudioData,
                                       &inLinesize,
                                       inNbChannels,
                                       inNbSamples,
                                       inSampleFmt,
                                       1);
    if(ret < 0){
        ERROR_BUF(ret);
        qDebug() << "av_samples_alloc_array_and_samples error:" << errbuf;
        goto end;
    }

    // 创建输出缓冲区
    ret = av_samples_alloc_array_and_samples(&outAudioData,
                                       &outLinesize,
                                       outNbChannels,
                                       outNbSamples,
                                       outSampleFmt,
                                       1);
    if(ret < 0){
        ERROR_BUF(ret);
        qDebug() << "av_samples_alloc_array_and_samples error:" << errbuf;
        goto end;
    }


    if(!inFile.open(QFile::ReadOnly)){
        qDebug() << "file open error:" << inFilename;
        goto end;
    }


    if(!outFile.open(QFile::WriteOnly)){
        qDebug() << "file open error:" << outFilename;
        goto end;
    }

    // inAudioData[0] == *inAudioData
    while ( (len = inFile.read((char *)inAudioData[0],inLinesize)) > 0) {
        // 读取的样本数量
        inNbSamples = len / inBytesPerSample;

        // 重采样(返回值转换后的样本数量)
        ret = swr_convert(ctx,
                          outAudioData,outNbSamples,
                          (const uint8_t **)inAudioData,inNbSamples);

        if (ret < 0) {
            ERROR_BUF(ret);
            qDebug() << "swr_convert error:" << errbuf;
            goto end;
        }

        // 将转换后的数据写入到输出文件中,上面的ret就是样本数量
        // outAudioData[0] == *outAudioData
        outFile.write((char *)outAudioData[0],ret * outBytesPerSample);
        // int size = av_samples_get_buffer_size(nullptr,outChLayout,ret,outSampleFmt,1);
        // outFile.write((char *)outAudioData[0],size);
    }

    // 检查一下输出缓冲区是否还有残留的样本（已经重采样过的，转换过的）
    while ((ret = swr_convert(ctx,
                             outAudioData,outNbSamples,
                             nullptr,0))> 0) {
        outFile.write((char *)outAudioData[0],ret * outBytesPerSample);
    }

end:
    // 释放资源
    // 关闭文件
    inFile.close();
    outFile.close();

    // 释放输入缓冲区
    if(inAudioData){
        av_freep(&inAudioData[0]);
    }
    av_freep(&inAudioData);

    // 释放输出缓冲区
    if(outAudioData){
        av_freep(&outAudioData[0]);
    }
    av_free(&outAudioData);

    // 释放重采样上下文
    swr_free(&ctx);
}
